#pragma once

#include "Base/Types/String.h"
#include "Base/FileSystem/FileSystemPath.h"

//-------------------------------------------------------------------------

namespace EE::TypeSystem::Reflection
{
    enum class ReflectionMacroType
    {
        ReflectModule,
        ReflectEnum,
        ReflectType,
        ReflectProperty,
        Resource,
        ReflectedResource,
        EntityComponent,
        SingletonEntityComponent,
        EntitySystem,
        EntityWorldSystem,

        NumMacros,
        Unknown = NumMacros,
    };

    char const* GetReflectionMacroText( ReflectionMacroType macro );

    //-------------------------------------------------------------------------

    namespace Settings
    {

        //-------------------------------------------------------------------------
        // Core engine settings
        //-------------------------------------------------------------------------

        constexpr static char const* const g_engineNamespace = "EE";
        constexpr static char const* const g_engineNamespacePlusDelimiter = "EE::";
        constexpr static char const* const g_devToolsExclusionDefine = "-D EE_SHIPPING";

        //-------------------------------------------------------------------------
        // Projects
        //-------------------------------------------------------------------------

        constexpr static char const* const g_moduleNameExclusionFilters[] = { "ThirdParty" };

        struct ProjectNames
        {
            char const* m_pFullName; // The full name of the project in the solution
            char const* m_pShortName; // The short name of the project (used for module and typeinfo files)
        };

        ProjectNames const g_allowedProjectNames[] =
        {
            { "Esoterica.Base", "Base" },
            { "Esoterica.Engine.Runtime", "Engine" },
            { "Esoterica.Game.Runtime", "Game" },
            { "Esoterica.Engine.Tools", "EngineTools" },
            { "Esoterica.Game.Tools", "GameTools" }
        };

        constexpr static int const g_numAllowedProjects = sizeof( g_allowedProjectNames ) / sizeof( g_allowedProjectNames[0] );

        //-------------------------------------------------------------------------
        // Core folder structure settings
        //-------------------------------------------------------------------------

        constexpr static char const* const g_moduleDirectoryName = "_Module";
        constexpr static char const* const g_autogeneratedDirectoryName = "_AutoGenerated";
        constexpr static char const* const g_typeinfoFileSuffix = "typeinfo";
        constexpr static char const* const g_codegenFileSuffix = "codegen";
        constexpr static char const* const g_moduleAPIFileName = "API.h";
        constexpr static char const* const g_moduleFileSuffix = "Module.h";
        constexpr static char const* const g_runtimeTypeRegistrationHeaderPath = "RuntimeTypeRegistration.h";
        constexpr static char const* const g_toolsTypeRegistrationHeaderPath = "ToolsTypeRegistration.h";
        constexpr static char const* const g_reflectionDatabaseDirectoryPath = "\\..\\_Temp\\";
        constexpr static char const* const g_globalAutoGeneratedDirectory = "Code\\Applications\\Shared\\_AutoGenerated\\";

        char const * const g_filenameToIgnore[] = 
        {
            "IResource.h",
            "ReflectedType.h"
        };

        constexpr static int const g_numFilenamesToIgnore = sizeof( g_filenameToIgnore ) / sizeof( g_filenameToIgnore[0] );

        //-------------------------------------------------------------------------
        // Core class and type names
        //-------------------------------------------------------------------------

        constexpr static char const* const g_reflectedTypeInterfaceClassName = "IReflectedType";
        constexpr static char const* const g_baseEntityClassName = "Entity";
        constexpr static char const* const g_baseEntityComponentClassName = "EntityComponent";
        constexpr static char const* const g_baseEntitySystemClassName = "IEntitySystem";

        constexpr static char const* const g_baseResourceFullTypeName = "EE::Resource::IResource";

        //-------------------------------------------------------------------------
        // Clang Parser Settings
        //-------------------------------------------------------------------------

        char const* const g_includePaths[] =
        {
            "Code\\",
            "Code\\Base\\ThirdParty\\EA\\EABase\\include\\common\\",
            "Code\\Base\\ThirdParty\\EA\\EASTL\\include\\",
            "Code\\Base\\ThirdParty\\",
            "Code\\Base\\ThirdParty\\imgui\\",
            "External\\PhysX\\physx\\include\\",
            #if EE_ENABLE_NAVPOWER
            "External\\NavPower\\include\\"
            #endif
        };
    }

    //-------------------------------------------------------------------------

    namespace Utils
    {
        inline FileSystem::Path GetAutogeneratedDirectoryNameForProject( FileSystem::Path const& projectPath )
        {
            FileSystem::Path autogeneratedDirectoryPath = projectPath;
            autogeneratedDirectoryPath.Append( Settings::g_moduleDirectoryName, true );
            autogeneratedDirectoryPath.Append( Settings::g_autogeneratedDirectoryName, true );
            return autogeneratedDirectoryPath;
        }

        static FileSystem::Path GetAutogeneratedFilePath( FileSystem::Path const& parentDir, char const* pFilenameWithoutExtension, char const* pSuffix, char const* pExtension )
        {
            InlineString const filenameStr( InlineString::CtorSprintf(), "%s.%s.%s", pFilenameWithoutExtension, pSuffix, pExtension );
            return parentDir.GetAppended( filenameStr.c_str() );
        };

        inline bool IsFileUnderToolsProject( FileSystem::Path const& filePath )
        {
            auto const& filePathStr = filePath.GetString();

            if ( filePathStr.find( "\\EngineTools\\" ) != String::npos )
            {
                return true;
            }

            if ( filePathStr.find( "\\GameTools\\" ) != String::npos )
            {
                return true;
            }

            return false;
        }
    }
}